﻿using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;
using System.Threading;
using System;
using Microsoft.Extensions.DependencyInjection;
using CarparkBusiness;
using Microsoft.Extensions.Options;
using System.Diagnostics;
using System.Timers;
using Timer = System.Threading.Timer;

namespace CarparkIMS_CMS
{
    public class TimedHostedService : IHostedService, IDisposable
    {
        private long executionCount = 0;
        private readonly ILogger<TimedHostedService> _logger;
        private Timer _timer;

        public TimedHostedService(ILogger<TimedHostedService> logger)
        {
            _logger = logger;
        }

        public Task StartAsync(CancellationToken stoppingToken)
        {
            _logger.LogInformation("Timed Hosted Service running.");

            _timer = new Timer(DoWork, null, TimeSpan.Zero,TimeSpan.FromSeconds(60));

            return Task.CompletedTask;
        }

        private void DoWork(object state)
        {
            var count = Interlocked.Increment(ref executionCount);
            _logger.LogInformation("Timed Hosted Service is working. Count: {Count}", count);
        }

        public Task StopAsync(CancellationToken stoppingToken)
        {
            _logger.LogInformation($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss fff}][Timed Hosted Service is stopping.]");

           _timer?.Change(Timeout.Infinite, 0);
           //_timer?.Change(TimeSpan.FromSeconds(60).Seconds, 0); 
            return Task.CompletedTask;
        }

        public void Dispose()
        {
            _timer?.Dispose();
        }
    }

    internal interface IScopedProcessingService
    {
        Task DoWork(CancellationToken stoppingToken);
    }

    internal class ScopedProcessingService : IScopedProcessingService
    {
        private int executionCount = 0;
        private readonly ILogger _logger;

        public ScopedProcessingService(ILogger<ScopedProcessingService> logger)
        {
            _logger = logger;
        }

        public async Task DoWork(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                executionCount++;
                _logger.LogInformation(
                    "Scoped Processing Service is working. Count: {Count}", executionCount);

                await Task.Delay(10000, stoppingToken);
            }
        }
    }

    public class ConsumeScopedServiceHostedService : BackgroundService
    {
        private readonly ILogger<ConsumeScopedServiceHostedService> _logger;

        public ConsumeScopedServiceHostedService(IServiceProvider services,
            ILogger<ConsumeScopedServiceHostedService> logger)
        {
            Services = services;
            _logger = logger;
        }

        public IServiceProvider Services { get; }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            _logger.LogInformation(
                "Consume Scoped Service Hosted Service running.");

            await DoWork(stoppingToken);
        }

        private async Task DoWork(CancellationToken stoppingToken)
        {
            _logger.LogInformation(
                "Consume Scoped Service Hosted Service is working.");

            using (var scope = Services.CreateScope())
            {
                var scopedProcessingService =
                    scope.ServiceProvider
                        .GetRequiredService<IScopedProcessingService>();
                await scopedProcessingService.DoWork(stoppingToken);
            }
        }

        public override async Task StopAsync(CancellationToken stoppingToken)
        {
            _logger.LogInformation(
                "Consume Scoped Service Hosted Service is stopping.");

            await base.StopAsync(stoppingToken);
        }
    }

    //========================================================
    public class ScopedWokerService : BackgroundService
    {
        public IServiceProvider Services { get; }
        private static ILogger<ScopedWokerService> _logger;

        public ScopedWokerService(IServiceProvider services, ILogger<ScopedWokerService> logger)
        {
            Services = services;
            _logger = logger;
        }
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            _logger.LogInformation("Consume Scoped Service Hosted Service running.");
            await DoWork(stoppingToken);
        }

        private async Task DoWork(CancellationToken stoppingToken)
        {
            _logger.LogInformation("Consume Scoped Service Hosted Service is working.");

            using (var scope = Services.CreateScope())
            {
                var scopedService =
                    scope.ServiceProvider
                        .GetRequiredService<IScopedService>();

                await scopedService.DoWork(stoppingToken);
            }
        }
        public override async Task StopAsync(CancellationToken stoppingToken)
        {
            _logger.LogInformation(
               $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss fff}][FUNC:StopAsync]Consume Scoped Service Hosted Service is stopping.");

            await base.StopAsync(stoppingToken);
        }
    }

    internal class ScopedService : IScopedService
    {
        private static int needToClearCount = 0;
        private int executionCount = 0;
        private static ILogger<ScopedService> _logger;
        private static ParkingSetting _ParkingSetting { get; set; }
        public ScopedService(ILogger<ScopedService> logger, IOptions<ParkingSetting> parkingSetting)
        {
            _logger = logger;
            _ParkingSetting = parkingSetting.Value;
        }

        public async Task DoWork(CancellationToken stoppingToken)
        {
            if (!stoppingToken.IsCancellationRequested)  //while
            {
                 executionCount++; 
                _logger.LogInformation($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss fff}] [FUNC::ScopedService::DoWork][PER HOUR [EXEC COUNT={executionCount}]");
                await Task.Delay(3000, stoppingToken);
                await TaskMainPortal();

                //async Task TaskAsync() => await Task.Run(async () => await TaskMainPortal());
                //await TaskAsync();
            }
            //executionCount++;
            //_logger.LogInformation($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss fff}] [FUNC::ScopedService::DoWork][PER HOUR [EXEC COUNT={executionCount}]");
            //await TaskMainPortal();
        }

        public static async Task TaskMainPortal()
        {
            await Task.Delay(0);
            string[] args = new[] { "x", "y" };
            //-------------------------------------------------------------
            var watch = new Stopwatch();
            ////Config Service  2022-12-30
            //var services = new ServiceCollection();
            //TaskStartUp.ConfigureServices(services);
            //var serviceProvider = services.BuildServiceProvider();

            await CarParkingScheduleTask.RunTask(args, _ParkingSetting.IntervalMinutes);
            
            System.Timers.Timer timer = new System.Timers.Timer();
            timer.AutoReset = true;
            timer.Interval = 60000 * 60;  //per one hour
            timer.Elapsed += new ElapsedEventHandler(Tick);
            timer.Start();
        }

        public static void Tick(object sender, System.Timers.ElapsedEventArgs e)
        {
            if (needToClearCount > 120)
            {
                needToClearCount = 0;
                Console.Clear();
            }
            string loggerLine = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss fff}] [SCOPED SERVICE IS RUNNING][TICK CHECK]";
            _logger.LogInformation(loggerLine);

           needToClearCount++;
        }
    }

    internal interface IScopedService
    {
        Task DoWork(CancellationToken stoppingToken);
    }
}
